"""
Case Type   : CM_Tools
Case Name   : CM备节点异常
Create At   : 2025/5/21
Owner       : ningyali
Description :
    1.查看集群状态
    2.CM备节点异常（kill掉CM相关进程）
    3.查看集群状态
    4.再次查看集群状态
Expect      :
    1.集群状态正常，无数据追赶
    2.kill掉CM备节点相关进程成功，查看无相关进程
    3.CM备节点down掉，且对应DN实例状态显示down
    4.kill掉的CM备节点自主恢复，状态正常
History     :
"""

import os
import re
import time
import unittest

from testcase.utils.ComInstall import CmInstall
from testcase.utils.ComInstall import CmUnInstall
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class CMServer(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.root_nodes = (Node('PrimaryRoot'), Node('Standby1Root'),
                           Node('Standby2Root'))
        self.user_nodes = (Node('PrimaryDbUser'), Node('Standby1DbUser'),
                           Node('Standby2DbUser'))
        self.common = Common()
        self.constant = Constant()
        self.q_log_path = os.path.join(macro.DB_BACKUP_PATH, 'cm_query.log')
        self.q_cmd = f"source {macro.DB_ENV_PATH};cm_ctl query -v -C -i -d"

        text = '----prestep1:安装cm;expect:执行成功----'
        self.log.info(text)
        self.install_pkg_path = os.path.dirname(macro.DB_SCRIPT_PATH)
        self.cm = CmInstall(self.install_pkg_path, self.pri_sh.node.ssh_user)
        res = self.cm.update_xml_for_cm(*self.root_nodes)
        self.assertGreater(res.count('cmDir'), 1, f'执行失败: {text}')

        res = self.cm.cm_install(self.user_nodes[0])
        self.assertIn('Install CM tool success', res, f'执行失败: {text}')

    def test_trans(self):
        text = '----step1:查看集群状态;expect:集群状态正常，无数据追赶----'
        self.log.info(text)
        q_res = self.common.get_sh_result(self.user_nodes[0], self.q_cmd)
        self.assertIn('cluster_state   : Normal', q_res, f'执行失败: {text}')

        text = '----step2:CM备节点异常（kill掉CM相关进程）;' \
               'expect:kill掉CM备节点相关进程成功，查看无相关进程----'
        self.log.info(text)
        kill_cmd = f"ps ux|grep -E 'om_monitor|cm_agent|cm_server'|" \
                   f"grep -v grep|awk '{{{{print $2}}}}'|xargs kill -9;" \
                   f"ps ux"
        kill_res = self.common.get_sh_result(self.user_nodes[2], kill_cmd)
        self.assertNotIn('error', kill_res.lower(), f'执行失败: {text}')

        text = '----step3:查看集群状态;expect:CM备节点down掉，且对应DN实例状态显示down----'
        self.log.info(text)

        text = '----step4:再次查看集群状态;expect:kill掉的CM备节点自主恢复，状态正常----'
        self.log.info(text)
        self.log.info('因节点状态变化非即时，因此step3和step4合并，由循环查询，中间态为Down，完成态为Normal即可')
        expect1 = f'{self.user_nodes[2].db_host}.*?Down'
        expect2 = f'{self.user_nodes[2].db_host}.*?Standby'
        expect3 = f'{self.user_nodes[2].db_host}.*?S Standby Normal'
        mid_flag = False
        final_flag = False
        for number in range(60):
            self.log.info(f'第{number + 1}次查询集群状态')
            q_res = self.common.get_sh_result(self.user_nodes[0], self.q_cmd)
            regex_res1 = re.findall(expect1, q_res)
            regex_res2 = re.findall(expect2, q_res)
            regex_res3 = re.findall(expect3, q_res)
            self.log.info(f'regex_res1:{regex_res1}')
            self.log.info(f'regex_res2:{regex_res2}')
            self.log.info(f'regex_res3:{regex_res3}')
            if len(regex_res1) == 2:
                mid_flag = True
            if len(regex_res2) == 2 and len(regex_res3) == 1:
                final_flag = True
            if mid_flag and final_flag:
                break
            time.sleep(1)
            self.log.info('\n\n\n')
        self.assertTrue(mid_flag and final_flag, f'执行失败: {text}')

    def tearDown(self):
        text = '----poststep1:还原集群;expect:执行成功----'
        self.log.info(text)
        q_res = self.common.get_sh_result(self.user_nodes[0], self.q_cmd)
        if 'Standby Normal' in q_res.splitlines()[-1].split('|')[0]:
            switch_cmd = f"source {macro.DB_ENV_PATH}; cm_ctl switchover -a;"
            self.common.get_sh_result(self.user_nodes[0], switch_cmd)
            time.sleep(5)
            q_res = self.common.get_sh_result(self.user_nodes[0], self.q_cmd)

        text = '----poststep2:卸载cm;expect:执行成功----'
        self.log.info(text)
        self.un_cm = CmUnInstall(self.install_pkg_path,
                                 self.pri_sh.node.ssh_user)
        res = self.un_cm.cm_uninstall(
            self.user_nodes[0], '--deleteData --deleteBinary')

        self.assertTrue(
            'Primary Normal' in q_res and q_res.count('Standby Normal') == 2,
            f'执行失败: {text}')
        self.assertIn('Uninstall CM tool success', res, f'执行失败: {text}')
        self.log.info(f'-----{os.path.basename(__file__)} end-----')
